{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Chapter 16 – Natural Language Processing with RNNs and Attention**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "_This notebook contains all the sample code in chapter 16._"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Setup"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, let's import a few common modules, ensure MatplotLib plots figures inline and prepare a function to save the figures. We also check that Python 3.5 or later is installed (although Python 2.x may work, it is deprecated so we strongly recommend you use Python 3 instead), as well as Scikit-Learn ≥0.20 and TensorFlow ≥2.0-preview."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Python ≥3.5 is required\n",
    "import sys\n",
    "assert sys.version_info >= (3, 5)\n",
    "\n",
    "# Scikit-Learn ≥0.20 is required\n",
    "import sklearn\n",
    "assert sklearn.__version__ >= \"0.20\"\n",
    "\n",
    "# TensorFlow ≥2.0-preview is required\n",
    "import tensorflow as tf\n",
    "from tensorflow import keras\n",
    "assert tf.__version__ >= \"2.0\"\n",
    "\n",
    "# Common imports\n",
    "import numpy as np\n",
    "import os\n",
    "\n",
    "# to make this notebook's output stable across runs\n",
    "np.random.seed(42)\n",
    "tf.random.set_seed(42)\n",
    "\n",
    "# To plot pretty figures\n",
    "%matplotlib inline\n",
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "mpl.rc('axes', labelsize=14)\n",
    "mpl.rc('xtick', labelsize=12)\n",
    "mpl.rc('ytick', labelsize=12)\n",
    "\n",
    "# Where to save the figures\n",
    "PROJECT_ROOT_DIR = \".\"\n",
    "CHAPTER_ID = \"nlp\"\n",
    "IMAGES_PATH = os.path.join(PROJECT_ROOT_DIR, \"images\", CHAPTER_ID)\n",
    "os.makedirs(IMAGES_PATH, exist_ok=True)\n",
    "\n",
    "def save_fig(fig_id, tight_layout=True, fig_extension=\"png\", resolution=300):\n",
    "    path = os.path.join(IMAGES_PATH, fig_id + \".\" + fig_extension)\n",
    "    print(\"Saving figure\", fig_id)\n",
    "    if tight_layout:\n",
    "        plt.tight_layout()\n",
    "    plt.savefig(path, format=fig_extension, dpi=resolution)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Char-RNN"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Splitting a sequence into batches of shuffled windows"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For example, let's split the sequence 0 to 14 into windows of length 5, each shifted by 2 (e.g.,`[0, 1, 2, 3, 4]`, `[2, 3, 4, 5, 6]`, etc.), then shuffle them, and split them into inputs (the first 4 steps) and targets (the last 4 steps) (e.g., `[2, 3, 4, 5, 6]` would be split into `[[2, 3, 4, 5], [3, 4, 5, 6]]`), then create batches of 3 such input/target pairs:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "____________________ Batch 0 \n",
      "X_batch\n",
      "[[6 7 8 9]\n",
      " [2 3 4 5]\n",
      " [4 5 6 7]]\n",
      "===== \n",
      "Y_batch\n",
      "[[ 7  8  9 10]\n",
      " [ 3  4  5  6]\n",
      " [ 5  6  7  8]]\n",
      "____________________ Batch 1 \n",
      "X_batch\n",
      "[[ 0  1  2  3]\n",
      " [ 8  9 10 11]\n",
      " [10 11 12 13]]\n",
      "===== \n",
      "Y_batch\n",
      "[[ 1  2  3  4]\n",
      " [ 9 10 11 12]\n",
      " [11 12 13 14]]\n"
     ]
    }
   ],
   "source": [
    "np.random.seed(42)\n",
    "tf.random.set_seed(42)\n",
    "\n",
    "n_steps = 5\n",
    "dataset = tf.data.Dataset.from_tensor_slices(tf.range(15))\n",
    "dataset = dataset.window(n_steps, shift=2, drop_remainder=True)\n",
    "dataset = dataset.flat_map(lambda window: window.batch(n_steps))\n",
    "dataset = dataset.shuffle(10).map(lambda window: (window[:-1], window[1:]))\n",
    "dataset = dataset.batch(3).prefetch(1)\n",
    "for index, (X_batch, Y_batch) in enumerate(dataset):\n",
    "    print(\"_\" * 20, \"Batch\", index, \"\\nX_batch\")\n",
    "    print(X_batch.numpy())\n",
    "    print(\"=\" * 5, \"\\nY_batch\")\n",
    "    print(Y_batch.numpy())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loading the Data and Preparing the Dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "shakespeare_url = \"https://raw.githubusercontent.com/karpathy/char-rnn/master/data/tinyshakespeare/input.txt\"\n",
    "filepath = keras.utils.get_file(\"shakespeare.txt\", shakespeare_url)\n",
    "with open(filepath) as f:\n",
    "    shakespeare_text = f.read()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "First Citizen:\n",
      "Before we proceed any further, hear me speak.\n",
      "\n",
      "All:\n",
      "Speak, speak.\n",
      "\n",
      "First Citizen:\n",
      "You are all resolved rather to die than to famish?\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(shakespeare_text[:148])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"\\n !$&',-.3:;?abcdefghijklmnopqrstuvwxyz\""
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"\".join(sorted(set(shakespeare_text.lower())))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "tokenizer = keras.preprocessing.text.Tokenizer(char_level=True)\n",
    "tokenizer.fit_on_texts(shakespeare_text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[[20, 6, 9, 8, 3]]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tokenizer.texts_to_sequences([\"First\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['f i r s t']"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tokenizer.sequences_to_texts([[20, 6, 9, 8, 3]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "max_id = len(tokenizer.word_index) # number of distinct characters\n",
    "dataset_size = tokenizer.document_count # total number of characters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "[encoded] = np.array(tokenizer.texts_to_sequences([shakespeare_text])) - 1\n",
    "train_size = dataset_size * 90 // 100\n",
    "dataset = tf.data.Dataset.from_tensor_slices(encoded[:train_size])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "n_steps = 100\n",
    "window_length = n_steps + 1 # target = input shifted 1 character ahead\n",
    "dataset = dataset.repeat().window(window_length, shift=1, drop_remainder=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "dataset = dataset.flat_map(lambda window: window.batch(window_length))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(42)\n",
    "tf.random.set_seed(42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "batch_size = 32\n",
    "dataset = dataset.shuffle(10000).batch(batch_size)\n",
    "dataset = dataset.map(lambda windows: (windows[:, :-1], windows[:, 1:]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "dataset = dataset.map(\n",
    "    lambda X_batch, Y_batch: (tf.one_hot(X_batch, depth=max_id), Y_batch))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "dataset = dataset.prefetch(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(32, 100, 39) (32, 100)\n"
     ]
    }
   ],
   "source": [
    "for X_batch, Y_batch in dataset.take(1):\n",
    "    print(X_batch.shape, Y_batch.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating and Training the Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/10\n",
      "31370/31370 [==============================] - 6063s 193ms/step - loss: 1.7662\n",
      "Epoch 2/10\n",
      "31370/31370 [==============================] - 5744s 183ms/step - loss: 1.6649\n",
      "Epoch 3/10\n",
      "31370/31370 [==============================] - 5320s 170ms/step - loss: 1.6508\n",
      "Epoch 4/10\n",
      "31370/31370 [==============================] - 5318s 170ms/step - loss: 1.6400\n",
      "Epoch 5/10\n",
      "31370/31370 [==============================] - 5318s 170ms/step - loss: 1.6359\n",
      "Epoch 6/10\n",
      "31370/31370 [==============================] - 5316s 169ms/step - loss: 1.6344\n",
      "Epoch 7/10\n",
      "31370/31370 [==============================] - 5489s 175ms/step - loss: 1.6336\n",
      "Epoch 8/10\n",
      "31370/31370 [==============================] - 5638s 180ms/step - loss: 1.6277\n",
      "Epoch 9/10\n",
      "31370/31370 [==============================] - 5709s 182ms/step - loss: 1.6309\n",
      "Epoch 10/10\n",
      "31370/31370 [==============================] - 6107s 195ms/step - loss: 1.6317\n"
     ]
    }
   ],
   "source": [
    "model = keras.models.Sequential([\n",
    "    keras.layers.GRU(128, return_sequences=True, input_shape=[None, max_id],\n",
    "                     dropout=0.2, recurrent_dropout=0.2),\n",
    "    keras.layers.GRU(128, return_sequences=True,\n",
    "                     dropout=0.2, recurrent_dropout=0.2),\n",
    "    keras.layers.TimeDistributed(keras.layers.Dense(max_id,\n",
    "                                                    activation=\"softmax\"))\n",
    "])\n",
    "model.compile(loss=\"sparse_categorical_crossentropy\", optimizer=\"adam\")\n",
    "history = model.fit(dataset, steps_per_epoch=train_size // batch_size,\n",
    "                    epochs=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using the Model to Generate Text"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "def preprocess(texts):\n",
    "    X = np.array(tokenizer.texts_to_sequences(texts)) - 1\n",
    "    return tf.one_hot(X, max_id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'u'"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_new = preprocess([\"How are yo\"])\n",
    "Y_pred = model.predict_classes(X_new)\n",
    "tokenizer.sequences_to_texts(Y_pred + 1)[0][-1] # 1st sentence, last char"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0, 1, 0, 2, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 2, 1, 0, 2, 1,\n",
       "        0, 1, 2, 1, 1, 1, 2, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 2]])"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.random.set_seed(42)\n",
    "\n",
    "tf.random.categorical([[np.log(0.5), np.log(0.4), np.log(0.1)]], num_samples=40).numpy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "def next_char(text, temperature=1):\n",
    "    X_new = preprocess([text])\n",
    "    y_proba = model.predict(X_new)[0, -1:, :]\n",
    "    rescaled_logits = tf.math.log(y_proba) / temperature\n",
    "    char_id = tf.random.categorical(rescaled_logits, num_samples=1) + 1\n",
    "    return tokenizer.sequences_to_texts(char_id.numpy())[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'u'"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.random.set_seed(42)\n",
    "\n",
    "next_char(\"How are yo\", temperature=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "def complete_text(text, n_chars=50, temperature=1):\n",
    "    for _ in range(n_chars):\n",
    "        text += next_char(text, temperature)\n",
    "    return text"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the belly the great and who shall be the belly the \n"
     ]
    }
   ],
   "source": [
    "tf.random.set_seed(42)\n",
    "\n",
    "print(complete_text(\"t\", temperature=0.2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "thing? or why you gremio.\n",
      "who make which the first \n"
     ]
    }
   ],
   "source": [
    "print(complete_text(\"t\", temperature=1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "th no cce:\n",
      "yeolg-hormer firi. a play asks.\n",
      "fol rusb\n"
     ]
    }
   ],
   "source": [
    "print(complete_text(\"t\", temperature=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Stateful RNN"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "tf.random.set_seed(42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "dataset = tf.data.Dataset.from_tensor_slices(encoded[:train_size])\n",
    "dataset = dataset.window(window_length, shift=n_steps, drop_remainder=True)\n",
    "dataset = dataset.flat_map(lambda window: window.batch(window_length))\n",
    "dataset = dataset.repeat().batch(1)\n",
    "dataset = dataset.map(lambda windows: (windows[:, :-1], windows[:, 1:]))\n",
    "dataset = dataset.map(\n",
    "    lambda X_batch, Y_batch: (tf.one_hot(X_batch, depth=max_id), Y_batch))\n",
    "dataset = dataset.prefetch(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "batch_size = 32\n",
    "encoded_parts = np.array_split(encoded[:train_size], batch_size)\n",
    "datasets = []\n",
    "for encoded_part in encoded_parts:\n",
    "    dataset = tf.data.Dataset.from_tensor_slices(encoded_part)\n",
    "    dataset = dataset.window(window_length, shift=n_steps, drop_remainder=True)\n",
    "    dataset = dataset.flat_map(lambda window: window.batch(window_length))\n",
    "    datasets.append(dataset)\n",
    "dataset = tf.data.Dataset.zip(tuple(datasets)).map(lambda *windows: tf.stack(windows))\n",
    "dataset = dataset.repeat().map(lambda windows: (windows[:, :-1], windows[:, 1:]))\n",
    "dataset = dataset.map(\n",
    "    lambda X_batch, Y_batch: (tf.one_hot(X_batch, depth=max_id), Y_batch))\n",
    "dataset = dataset.prefetch(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = keras.models.Sequential([\n",
    "    keras.layers.GRU(128, return_sequences=True, stateful=True,\n",
    "                     dropout=0.2, recurrent_dropout=0.2,\n",
    "                     batch_input_shape=[batch_size, None, max_id]),\n",
    "    keras.layers.GRU(128, return_sequences=True, stateful=True,\n",
    "                     dropout=0.2, recurrent_dropout=0.2),\n",
    "    keras.layers.TimeDistributed(keras.layers.Dense(max_id,\n",
    "                                                    activation=\"softmax\"))\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ResetStatesCallback(keras.callbacks.Callback):\n",
    "    def on_epoch_begin(self, epoch, logs):\n",
    "        self.model.reset_states()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/50\n",
      "313/313 [==============================] - 101s 322ms/step - loss: 2.6180\n",
      "Epoch 2/50\n",
      "313/313 [==============================] - 98s 312ms/step - loss: 2.2312\n",
      "Epoch 3/50\n",
      "313/313 [==============================] - 96s 306ms/step - loss: 2.2992\n",
      "Epoch 4/50\n",
      "313/313 [==============================] - 96s 308ms/step - loss: 2.4599\n",
      "Epoch 5/50\n",
      "313/313 [==============================] - 97s 309ms/step - loss: 2.4062\n",
      "Epoch 6/50\n",
      "313/313 [==============================] - 97s 310ms/step - loss: 2.0630\n",
      "Epoch 7/50\n",
      "313/313 [==============================] - 97s 311ms/step - loss: 2.0933\n",
      "Epoch 8/50\n",
      "313/313 [==============================] - 97s 309ms/step - loss: 2.0784\n",
      "Epoch 9/50\n",
      "313/313 [==============================] - 95s 304ms/step - loss: 2.0101\n",
      "Epoch 10/50\n",
      "313/313 [==============================] - 95s 302ms/step - loss: 1.9146\n",
      "Epoch 11/50\n",
      "313/313 [==============================] - 97s 309ms/step - loss: 1.9204\n",
      "Epoch 12/50\n",
      "313/313 [==============================] - 95s 305ms/step - loss: 1.9049\n",
      "Epoch 13/50\n",
      "313/313 [==============================] - 92s 295ms/step - loss: 1.8894\n",
      "Epoch 14/50\n",
      "313/313 [==============================] - 93s 296ms/step - loss: 1.8397\n",
      "Epoch 15/50\n",
      "313/313 [==============================] - 93s 296ms/step - loss: 1.8147\n",
      "Epoch 16/50\n",
      "313/313 [==============================] - 92s 293ms/step - loss: 1.8147\n",
      "Epoch 17/50\n",
      "313/313 [==============================] - 92s 295ms/step - loss: 1.7741\n",
      "Epoch 18/50\n",
      "<<30 more lines>>\n",
      "313/313 [==============================] - 93s 298ms/step - loss: 1.6102\n",
      "Epoch 34/50\n",
      "313/313 [==============================] - 93s 298ms/step - loss: 1.6063\n",
      "Epoch 35/50\n",
      "313/313 [==============================] - 96s 306ms/step - loss: 1.6022\n",
      "Epoch 36/50\n",
      "313/313 [==============================] - 91s 291ms/step - loss: 1.5984\n",
      "Epoch 37/50\n",
      "313/313 [==============================] - 91s 291ms/step - loss: 1.5964\n",
      "Epoch 38/50\n",
      "313/313 [==============================] - 92s 293ms/step - loss: 1.5924\n",
      "Epoch 39/50\n",
      "313/313 [==============================] - 97s 310ms/step - loss: 1.5903\n",
      "Epoch 40/50\n",
      "313/313 [==============================] - 93s 298ms/step - loss: 1.5882\n",
      "Epoch 41/50\n",
      "313/313 [==============================] - 95s 303ms/step - loss: 1.5867\n",
      "Epoch 42/50\n",
      "313/313 [==============================] - 92s 294ms/step - loss: 1.5826\n",
      "Epoch 43/50\n",
      "313/313 [==============================] - 92s 294ms/step - loss: 1.5817\n",
      "Epoch 44/50\n",
      "313/313 [==============================] - 92s 295ms/step - loss: 1.5796\n",
      "Epoch 45/50\n",
      "313/313 [==============================] - 92s 295ms/step - loss: 1.5765\n",
      "Epoch 46/50\n",
      "313/313 [==============================] - 92s 294ms/step - loss: 1.5741\n",
      "Epoch 47/50\n",
      "313/313 [==============================] - 92s 295ms/step - loss: 1.5733\n",
      "Epoch 48/50\n",
      "313/313 [==============================] - 92s 293ms/step - loss: 1.5706\n",
      "Epoch 49/50\n",
      "313/313 [==============================] - 90s 289ms/step - loss: 1.5703\n",
      "Epoch 50/50\n",
      "313/313 [==============================] - 90s 288ms/step - loss: 1.5666\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0xd37b57908>"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.compile(loss=\"sparse_categorical_crossentropy\", optimizer=\"adam\")\n",
    "steps_per_epoch = train_size // batch_size // n_steps\n",
    "model.fit(dataset, steps_per_epoch=steps_per_epoch, epochs=50,\n",
    "                   callbacks=[ResetStatesCallback()])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To use the model with different batch sizes, we need to create a stateless copy. We can get rid of dropout since it is only used during training:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "stateless_model = keras.models.Sequential([\n",
    "    keras.layers.GRU(128, return_sequences=True, input_shape=[None, max_id]),\n",
    "    keras.layers.GRU(128, return_sequences=True),\n",
    "    keras.layers.TimeDistributed(keras.layers.Dense(max_id,\n",
    "                                                    activation=\"softmax\"))\n",
    "])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To set the weights, we first need to build the model (so the weights get created):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "stateless_model.build(tf.TensorShape([None, None, max_id]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "stateless_model.set_weights(model.get_weights())\n",
    "model = stateless_model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torp:\n",
      "unto most breathe blood him sight,\n",
      "which rest\n"
     ]
    }
   ],
   "source": [
    "tf.random.set_seed(42)\n",
    "\n",
    "print(complete_text(\"t\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Sentiment Analysis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "tf.random.set_seed(42)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can load the IMDB dataset easily:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "(X_train, y_test), (X_valid, y_test) = keras.datasets.imdb.load_data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 14, 22, 16, 43, 530, 973, 1622, 1385, 65]"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X_train[0][:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'<sos> this film was just brilliant casting location scenery story'"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "word_index = keras.datasets.imdb.get_word_index()\n",
    "id_to_word = {id_ + 3: word for word, id_ in word_index.items()}\n",
    "for id_, token in enumerate((\"<pad>\", \"<sos>\", \"<unk>\")):\n",
    "    id_to_word[id_] = token\n",
    "\" \".join([id_to_word[id_] for id_ in X_train[0][:10]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow_datasets as tfds\n",
    "\n",
    "datasets, info = tfds.load(\"imdb_reviews\", as_supervised=True, with_info=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dict_keys(['test', 'train'])"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "datasets.keys()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_size = info.splits[\"train\"].num_examples\n",
    "test_size = info.splits[\"test\"].num_examples"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(25000, 25000)"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_size, test_size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Review: This was soul-provoking! I am an Iranian, and living in th 21st century, I didn't know that such big tribes have been living in such conditions at the time of my grandfather!<br /><br />You see that t ...\n",
      "Label: 1 = Positive\n",
      "\n",
      "Review: A very close and sharp discription of the bubbling and dynamic emotional world of specialy one 18year old guy, that makes his first experiences in his gay love to an other boy, during an vacation with ...\n",
      "Label: 1 = Positive\n",
      "\n"
     ]
    }
   ],
   "source": [
    "for X_batch, y_batch in datasets[\"train\"].batch(2).take(1):\n",
    "    for review, label in zip(X_batch.numpy(), y_batch.numpy()):\n",
    "        print(\"Review:\", review.decode(\"utf-8\")[:200], \"...\")\n",
    "        print(\"Label:\", label, \"= Positive\" if label else \"= Negative\")\n",
    "        print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "def preprocess(X_batch, y_batch):\n",
    "    X_batch = tf.strings.substr(X_batch, 0, 300)\n",
    "    X_batch = tf.strings.regex_replace(X_batch, rb\"<br\\s*/?>\", b\" \")\n",
    "    X_batch = tf.strings.regex_replace(X_batch, b\"[^a-zA-Z']\", b\" \")\n",
    "    X_batch = tf.strings.split(X_batch)\n",
    "    return X_batch.to_tensor(default_value=b\"<pad>\"), y_batch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<tf.Tensor: id=235, shape=(2, 57), dtype=string, numpy=\n",
       " array([[b'This', b'was', b'soul', b'provoking', b'I', b'am', b'an',\n",
       "         b'Iranian', b'and', b'living', b'in', b'th', b'st', b'century',\n",
       "         b'I', b\"didn't\", b'know', b'that', b'such', b'big', b'tribes',\n",
       "         b'have', b'been', b'living', b'in', b'such', b'conditions',\n",
       "         b'at', b'the', b'time', b'of', b'my', b'grandfather', b'You',\n",
       "         b'see', b'that', b'today', b'or', b'even', b'in', b'on', b'one',\n",
       "         b'side', b'of', b'the', b'world', b'a', b'lady', b'or', b'a',\n",
       "         b'baby', b'could', b'have', b'everything', b'served', b'for',\n",
       "         b'hi'],\n",
       "        [b'A', b'very', b'close', b'and', b'sharp', b'discription', b'of',\n",
       "         b'the', b'bubbling', b'and', b'dynamic', b'emotional', b'world',\n",
       "         b'of', b'specialy', b'one', b'year', b'old', b'guy', b'that',\n",
       "         b'makes', b'his', b'first', b'experiences', b'in', b'his',\n",
       "         b'gay', b'love', b'to', b'an', b'other', b'boy', b'during',\n",
       "         b'an', b'vacation', b'with', b'a', b'part', b'of', b'his',\n",
       "         b'family', b'I', b'liked', b'this', b'film', b'because', b'of',\n",
       "         b'his', b'extremly', b'clear', b'and', b'surrogated', b'sto',\n",
       "         b'<pad>', b'<pad>', b'<pad>', b'<pad>']], dtype=object)>,\n",
       " <tf.Tensor: id=128, shape=(2,), dtype=int64, numpy=array([1, 1])>)"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "preprocess(X_batch, y_batch)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [],
   "source": [
    "from collections import Counter\n",
    "\n",
    "vocabulary = Counter()\n",
    "for X_batch, y_batch in datasets[\"train\"].batch(32).map(preprocess):\n",
    "    for review in X_batch:\n",
    "        vocabulary.update(list(review.numpy()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(b'<pad>', 214077), (b'the', 61137), (b'a', 38564)]"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vocabulary.most_common()[:3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "53893"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(vocabulary)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "vocab_size = 10000\n",
    "truncated_vocabulary = [\n",
    "    word for word, count in vocabulary.most_common()[:vocab_size]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "22\n",
      "12\n",
      "11\n",
      "10000\n"
     ]
    }
   ],
   "source": [
    "word_to_id = {word: index for index, word in enumerate(truncated_vocabulary)}\n",
    "for word in b\"This movie was faaaaaantastic\".split():\n",
    "    print(word_to_id.get(word) or vocab_size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "words = tf.constant(truncated_vocabulary)\n",
    "word_ids = tf.range(len(truncated_vocabulary), dtype=tf.int64)\n",
    "vocab_init = tf.lookup.KeyValueTensorInitializer(words, word_ids)\n",
    "num_oov_buckets = 1000\n",
    "table = tf.lookup.StaticVocabularyTable(vocab_init, num_oov_buckets)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: id=126936, shape=(1, 4), dtype=int64, numpy=array([[   22,    12,    11, 10053]])>"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "table.lookup(tf.constant([b\"This movie was faaaaaantastic\".split()]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [],
   "source": [
    "def encode_words(X_batch, y_batch):\n",
    "    return table.lookup(X_batch), y_batch\n",
    "\n",
    "train_set = datasets[\"train\"].repeat().batch(32).map(preprocess)\n",
    "train_set = train_set.map(encode_words).prefetch(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tf.Tensor(\n",
      "[[    6    98     9 ...     0     0     0]\n",
      " [  185     2 10865 ...     0     0     0]\n",
      " [  719  2410  5630 ...     0     0     0]\n",
      " ...\n",
      " [    6    94    13 ...     0     0     0]\n",
      " [   14   498    16 ...     0     0     0]\n",
      " [  168     1  1633 ...     0     0     0]], shape=(32, 64), dtype=int64)\n",
      "tf.Tensor([1 1 1 1 1 1 1 1 0 0 1 1 0 1 1 1 0 1 1 1 0 0 1 1 1 1 1 1 0 1 0 0], shape=(32,), dtype=int64)\n"
     ]
    }
   ],
   "source": [
    "for X_batch, y_batch in train_set.take(1):\n",
    "    print(X_batch)\n",
    "    print(y_batch)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/5\n",
      "781/781 [==============================] - 102s 131ms/step - loss: 0.5378 - accuracy: 0.7238\n",
      "Epoch 2/5\n",
      "781/781 [==============================] - 87s 111ms/step - loss: 0.3485 - accuracy: 0.8567\n",
      "Epoch 3/5\n",
      "781/781 [==============================] - 87s 111ms/step - loss: 0.1877 - accuracy: 0.9332\n",
      "Epoch 4/5\n",
      "781/781 [==============================] - 87s 111ms/step - loss: 0.1236 - accuracy: 0.9573\n",
      "Epoch 5/5\n",
      "781/781 [==============================] - 87s 111ms/step - loss: 0.0964 - accuracy: 0.9667\n"
     ]
    }
   ],
   "source": [
    "embed_size = 128\n",
    "model = keras.models.Sequential([\n",
    "    keras.layers.Embedding(vocab_size + num_oov_buckets, embed_size,\n",
    "                           mask_zero=True, # not shown in the book\n",
    "                           input_shape=[None]),\n",
    "    keras.layers.GRU(128, return_sequences=True),\n",
    "    keras.layers.GRU(128),\n",
    "    keras.layers.Dense(1, activation=\"sigmoid\")\n",
    "])\n",
    "model.compile(loss=\"binary_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"])\n",
    "history = model.fit(train_set, steps_per_epoch=train_size // 32, epochs=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Or using manual masking:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/5\n",
      "781/781 [==============================] - 102s 131ms/step - loss: 0.5436 - accuracy: 0.7172\n",
      "Epoch 2/5\n",
      "781/781 [==============================] - 88s 113ms/step - loss: 0.3519 - accuracy: 0.8564\n",
      "Epoch 3/5\n",
      "781/781 [==============================] - 87s 111ms/step - loss: 0.1950 - accuracy: 0.9306\n",
      "Epoch 4/5\n",
      "781/781 [==============================] - 87s 111ms/step - loss: 0.1226 - accuracy: 0.9579\n",
      "Epoch 5/5\n",
      "781/781 [==============================] - 86s 110ms/step - loss: 0.0922 - accuracy: 0.9679\n"
     ]
    }
   ],
   "source": [
    "K = keras.backend\n",
    "embed_size = 128\n",
    "inputs = keras.layers.Input(shape=[None])\n",
    "mask = keras.layers.Lambda(lambda inputs: K.not_equal(inputs, 0))(inputs)\n",
    "z = keras.layers.Embedding(vocab_size + num_oov_buckets, embed_size)(inputs)\n",
    "z = keras.layers.GRU(128, return_sequences=True)(z, mask=mask)\n",
    "z = keras.layers.GRU(128)(z, mask=mask)\n",
    "outputs = keras.layers.Dense(1, activation=\"sigmoid\")(z)\n",
    "model = keras.models.Model(inputs=[inputs], outputs=[outputs])\n",
    "model.compile(loss=\"binary_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"])\n",
    "history = model.fit(train_set, steps_per_epoch=train_size // 32, epochs=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Reusing Pretrained Embeddings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "tf.random.set_seed(42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "TFHUB_CACHE_DIR = os.path.join(os.curdir, \"my_tfhub_cache\")\n",
    "os.environ[\"TFHUB_CACHE_DIR\"] = TFHUB_CACHE_DIR"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow_hub as hub\n",
    "\n",
    "model = keras.Sequential([\n",
    "    hub.KerasLayer(\"https://tfhub.dev/google/tf2-preview/nnlm-en-dim50/1\",\n",
    "                   dtype=tf.string, input_shape=[], output_shape=[50]),\n",
    "    keras.layers.Dense(128, activation=\"relu\"),\n",
    "    keras.layers.Dense(1, activation=\"sigmoid\")\n",
    "])\n",
    "model.compile(loss=\"binary_crossentropy\", optimizer=\"adam\",\n",
    "              metrics=[\"accuracy\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./my_tfhub_cache/82c4aaf4250ffb09088bd48368ee7fd00e5464fe.descriptor.txt\n",
      "./my_tfhub_cache/82c4aaf4250ffb09088bd48368ee7fd00e5464fe/saved_model.pb\n",
      "./my_tfhub_cache/82c4aaf4250ffb09088bd48368ee7fd00e5464fe/variables/variables.data-00000-of-00001\n",
      "./my_tfhub_cache/82c4aaf4250ffb09088bd48368ee7fd00e5464fe/variables/variables.index\n",
      "./my_tfhub_cache/82c4aaf4250ffb09088bd48368ee7fd00e5464fe/assets/tokens.txt\n"
     ]
    }
   ],
   "source": [
    "for dirpath, dirnames, filenames in os.walk(TFHUB_CACHE_DIR):\n",
    "    for filename in filenames:\n",
    "        print(os.path.join(dirpath, filename))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/5\n",
      "781/781 [==============================] - 119s 152ms/step - loss: 0.5499 - accuracy: 0.7230\n",
      "Epoch 2/5\n",
      "781/781 [==============================] - 119s 152ms/step - loss: 0.5133 - accuracy: 0.7486\n",
      "Epoch 3/5\n",
      "781/781 [==============================] - 117s 150ms/step - loss: 0.5078 - accuracy: 0.7518\n",
      "Epoch 4/5\n",
      "781/781 [==============================] - 118s 151ms/step - loss: 0.5042 - accuracy: 0.7540\n",
      "Epoch 5/5\n",
      "781/781 [==============================] - 122s 156ms/step - loss: 0.5010 - accuracy: 0.7574\n"
     ]
    }
   ],
   "source": [
    "import tensorflow_datasets as tfds\n",
    "\n",
    "datasets, info = tfds.load(\"imdb_reviews\", as_supervised=True, with_info=True)\n",
    "train_size = info.splits[\"train\"].num_examples\n",
    "batch_size = 32\n",
    "train_set = datasets[\"train\"].repeat().batch(batch_size).prefetch(1)\n",
    "history = model.fit(train_set, steps_per_epoch=train_size // batch_size, epochs=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Automatic Translation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [],
   "source": [
    "tf.random.set_seed(42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [],
   "source": [
    "vocab_size = 100\n",
    "embed_size = 10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow_addons as tfa\n",
    "\n",
    "encoder_inputs = keras.layers.Input(shape=[None], dtype=np.int32)\n",
    "decoder_inputs = keras.layers.Input(shape=[None], dtype=np.int32)\n",
    "sequence_lengths = keras.layers.Input(shape=[], dtype=np.int32)\n",
    "\n",
    "embeddings = keras.layers.Embedding(vocab_size, embed_size)\n",
    "encoder_embeddings = embeddings(encoder_inputs)\n",
    "decoder_embeddings = embeddings(decoder_inputs)\n",
    "\n",
    "encoder = keras.layers.LSTM(512, return_state=True)\n",
    "encoder_outputs, state_h, state_c = encoder(encoder_embeddings)\n",
    "encoder_state = [state_h, state_c]\n",
    "\n",
    "sampler = tfa.seq2seq.sampler.TrainingSampler()\n",
    "\n",
    "decoder_cell = keras.layers.LSTMCell(512)\n",
    "output_layer = keras.layers.Dense(vocab_size)\n",
    "decoder = tfa.seq2seq.basic_decoder.BasicDecoder(decoder_cell, sampler,\n",
    "                                                 output_layer=output_layer)\n",
    "final_outputs, final_state, final_sequence_lengths = decoder(\n",
    "    decoder_embeddings, initial_state=encoder_state,\n",
    "    sequence_length=sequence_lengths)\n",
    "Y_proba = tf.nn.softmax(final_outputs.rnn_output)\n",
    "\n",
    "model = keras.models.Model(\n",
    "    inputs=[encoder_inputs, decoder_inputs, sequence_lengths],\n",
    "    outputs=[Y_proba])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.compile(loss=\"sparse_categorical_crossentropy\", optimizer=\"adam\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/2\n",
      "1000/1000 [==============================] - 6s 6ms/sample - loss: 4.6054\n",
      "Epoch 2/2\n",
      "1000/1000 [==============================] - 5s 5ms/sample - loss: 4.6041"
     ]
    }
   ],
   "source": [
    "X = np.random.randint(100, size=10*1000).reshape(1000, 10)\n",
    "Y = np.random.randint(100, size=15*1000).reshape(1000, 15)\n",
    "X_decoder = np.c_[np.zeros((1000, 1)), Y[:, :-1]]\n",
    "seq_lengths = np.full([1000], 15)\n",
    "\n",
    "history = model.fit([X, X_decoder, seq_lengths], Y, epochs=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Bidirectional Recurrent Layers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential_2\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "gru_4 (GRU)                  (None, None, 10)          660       \n",
      "_________________________________________________________________\n",
      "bidirectional (Bidirectional (None, None, 20)          1320      \n",
      "=================================================================\n",
      "Total params: 1,980\n",
      "Trainable params: 1,980\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model = keras.models.Sequential([\n",
    "    keras.layers.GRU(10, return_sequences=True, input_shape=[None, 10]),\n",
    "    keras.layers.Bidirectional(keras.layers.GRU(10, return_sequences=True))\n",
    "])\n",
    "\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Positional Encoding"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PositionalEncoding(keras.layers.Layer):\n",
    "    def __init__(self, max_steps, max_dims, dtype=tf.float32, **kwargs):\n",
    "        super().__init__(dtype=dtype, **kwargs)\n",
    "        if max_dims % 2 == 1: max_dims += 1 # max_dims must be even\n",
    "        p, i = np.meshgrid(np.arange(max_steps), np.arange(max_dims // 2))\n",
    "        pos_emb = np.empty((1, max_steps, max_dims))\n",
    "        pos_emb[0, :, ::2] = np.sin(p / 10000**(2 * i / max_dims)).T\n",
    "        pos_emb[0, :, 1::2] = np.cos(p / 10000**(2 * i / max_dims)).T\n",
    "        self.positional_embedding = tf.constant(pos_emb.astype(self.dtype))\n",
    "    def call(self, inputs):\n",
    "        shape = tf.shape(inputs)\n",
    "        return inputs + self.positional_embedding[:, :shape[-2], :shape[-1]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [],
   "source": [
    "max_steps = 201\n",
    "max_dims = 512\n",
    "pos_emb = PositionalEncoding(max_steps, max_dims)\n",
    "PE = pos_emb(np.zeros((1, max_steps, max_dims), np.float32))[0].numpy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 648x360 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "i1, i2, crop_i = 100, 101, 150\n",
    "p1, p2, p3 = 22, 60, 35\n",
    "fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1, sharex=True, figsize=(9, 5))\n",
    "ax1.plot([p1, p1], [-1, 1], \"k--\", label=\"$p = {}$\".format(p1))\n",
    "ax1.plot([p2, p2], [-1, 1], \"k--\", label=\"$p = {}$\".format(p2), alpha=0.5)\n",
    "ax1.plot(p3, PE[p3, i1], \"bx\", label=\"$p = {}$\".format(p3))\n",
    "ax1.plot(PE[:,i1], \"b-\", label=\"$i = {}$\".format(i1))\n",
    "ax1.plot(PE[:,i2], \"r-\", label=\"$i = {}$\".format(i2))\n",
    "ax1.plot([p1, p2], [PE[p1, i1], PE[p2, i1]], \"bo\")\n",
    "ax1.plot([p1, p2], [PE[p1, i2], PE[p2, i2]], \"ro\")\n",
    "ax1.legend(loc=\"center right\", fontsize=14, framealpha=0.95)\n",
    "ax1.set_ylabel(\"$P_{(p,i)}$\", rotation=0, fontsize=16)\n",
    "ax1.grid(True, alpha=0.3)\n",
    "ax1.hlines(0, 0, max_steps - 1, color=\"k\", linewidth=1, alpha=0.3)\n",
    "ax1.axis([0, max_steps - 1, -1, 1])\n",
    "ax2.imshow(PE.T[:crop_i], cmap=\"gray\", interpolation=\"bilinear\", aspect=\"auto\")\n",
    "ax2.hlines(i1, 0, max_steps - 1, color=\"b\")\n",
    "cheat = 2 # need to raise the red line a bit, or else it hides the blue one\n",
    "ax2.hlines(i2+cheat, 0, max_steps - 1, color=\"r\")\n",
    "ax2.plot([p1, p1], [0, crop_i], \"k--\")\n",
    "ax2.plot([p2, p2], [0, crop_i], \"k--\", alpha=0.5)\n",
    "ax2.plot([p1, p2], [i2+cheat, i2+cheat], \"ro\")\n",
    "ax2.plot([p1, p2], [i1, i1], \"bo\")\n",
    "ax2.axis([0, max_steps - 1, 0, crop_i])\n",
    "ax2.set_xlabel(\"$p$\", fontsize=16)\n",
    "ax2.set_ylabel(\"$i$\", rotation=0, fontsize=16)\n",
    "plt.savefig(\"positional_embedding_plot\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [],
   "source": [
    "embed_size = 512; max_steps = 500; vocab_size = 10000\n",
    "encoder_inputs = keras.layers.Input(shape=[None], dtype=np.int32)\n",
    "decoder_inputs = keras.layers.Input(shape=[None], dtype=np.int32)\n",
    "embeddings = keras.layers.Embedding(vocab_size, embed_size)\n",
    "encoder_embeddings = embeddings(encoder_inputs)\n",
    "decoder_embeddings = embeddings(decoder_inputs)\n",
    "positional_encoding = PositionalEncoding(max_steps, max_dims=embed_size)\n",
    "encoder_in = positional_encoding(encoder_embeddings)\n",
    "decoder_in = positional_encoding(decoder_embeddings)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is a (very) simplified Transformer (the actual architecture has skip connections, layer norm, dense nets, and most importantly it uses Multi-Head Attention instead of regular Attention):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [],
   "source": [
    "for N in range(6):\n",
    "    encoder_attn = keras.layers.Attention(use_scale=True)\n",
    "    encoder_in = encoder_attn([encoder_in, encoder_in])\n",
    "    masked_decoder_attn = keras.layers.Attention(use_scale=True, causal=True)\n",
    "    decoder_in = masked_decoder_attn([decoder_in, decoder_in])\n",
    "    decoder_attn = keras.layers.Attention(use_scale=True)\n",
    "    final_enc = decoder_attn([decoder_in, encoder_in])\n",
    "\n",
    "output_layer = keras.layers.TimeDistributed(\n",
    "    keras.layers.Dense(vocab_size, activation=\"softmax\"))\n",
    "outputs = output_layer(final_enc)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here's a basic implementation of the `MultiHeadAttention` layer. One will likely be added to `keras.layers` in the near future. Note that `Conv1D` layers with `kernel_size=1` (and the default `padding=\"valid\"` and `strides=1`) is equivalent to a `TimeDistributed(Dense(...))` layer."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [],
   "source": [
    "K = keras.backend\n",
    "\n",
    "class MultiHeadAttention(keras.layers.Layer):\n",
    "    def __init__(self, n_heads, causal=False, use_scale=False, **kwargs):\n",
    "        self.n_heads = n_heads\n",
    "        self.causal = causal\n",
    "        self.use_scale = use_scale\n",
    "        super().__init__(**kwargs)\n",
    "    def build(self, batch_input_shape):\n",
    "        self.dims = batch_input_shape[0][-1]\n",
    "        self.q_dims, self.v_dims, self.k_dims = [self.dims // self.n_heads] * 3 # could be hyperparameters instead\n",
    "        self.q_linear = keras.layers.Conv1D(self.n_heads * self.q_dims, kernel_size=1, use_bias=False)\n",
    "        self.v_linear = keras.layers.Conv1D(self.n_heads * self.v_dims, kernel_size=1, use_bias=False)\n",
    "        self.k_linear = keras.layers.Conv1D(self.n_heads * self.k_dims, kernel_size=1, use_bias=False)\n",
    "        self.attention = keras.layers.Attention(causal=self.causal, use_scale=self.use_scale)\n",
    "        self.out_linear = keras.layers.Conv1D(self.dims, kernel_size=1, use_bias=False)\n",
    "        super().build(batch_input_shape)\n",
    "    def _multi_head_linear(self, inputs, linear):\n",
    "        shape = K.concatenate([K.shape(inputs)[:-1], [self.n_heads, -1]])\n",
    "        projected = K.reshape(linear(inputs), shape)\n",
    "        perm = K.permute_dimensions(projected, [0, 2, 1, 3])\n",
    "        return K.reshape(perm, [shape[0] * self.n_heads, shape[1], -1])\n",
    "    def call(self, inputs):\n",
    "        q = inputs[0]\n",
    "        v = inputs[1]\n",
    "        k = inputs[2] if len(inputs) > 2 else v\n",
    "        shape = K.shape(q)\n",
    "        q_proj = self._multi_head_linear(q, self.q_linear)\n",
    "        v_proj = self._multi_head_linear(v, self.v_linear)\n",
    "        k_proj = self._multi_head_linear(k, self.k_linear)\n",
    "        multi_attended = self.attention([q_proj, v_proj, k_proj])\n",
    "        shape_attended = K.shape(multi_attended)\n",
    "        reshaped_attended = K.reshape(multi_attended, [shape[0], self.n_heads, shape_attended[1], shape_attended[2]])\n",
    "        perm = K.permute_dimensions(reshaped_attended, [0, 2, 1, 3])\n",
    "        concat = K.reshape(perm, [shape[0], shape_attended[1], -1])\n",
    "        return self.out_linear(concat)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "TensorShape([2, 50, 512])"
      ]
     },
     "execution_count": 77,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Q = np.random.rand(2, 50, 512)\n",
    "V = np.random.rand(2, 80, 512)\n",
    "multi_attn = MultiHeadAttention(8)\n",
    "multi_attn([Q, V]).shape"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  },
  "nav_menu": {},
  "toc": {
   "navigate_menu": true,
   "number_sections": true,
   "sideBar": true,
   "threshold": 6,
   "toc_cell": false,
   "toc_section_display": "block",
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
